package com.loong.tool.code;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

import javax.imageio.ImageIO;

/**
 * 验证码图片生成器
 *
 * @author 张成轩
 */
public class VCode {

	/** 字符上的固定空余空间 */
	private static final float CHAR_BLANK_PROP = 0.2F;

	/** 默认背景 */
	public static final Color DEFAULT_BG = Color.WHITE;
	/** 默认代码列表 */
	public static final Character[] DEFAULT_CODES = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N',
			'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9' };
	/** 默认字体颜色列表 */
	public static final Color[] DEFAULT_COLORS = { Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GREEN,
			Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED };
	/** 默认字体类型列表 */
	public static final String[] DEFAULT_FONTS = { "Arial", "Garamond", "Georgia" };
	/** 默认字体样式列表 */
	public static final Integer[] DEFAULT_STYLES = { Font.BOLD, Font.BOLD + Font.ITALIC };
	/** 图片代码占比 */
	private static final float PROP = 0.9F;

	/** 随机数生成器 */
	private static Random random = new Random();

	/**
	 * 获取图片验证对象
	 * 
	 * @param width 图片宽度
	 * @param height 图片高度
	 * @param count 字符数量
	 * @return 图片验证对象
	 */
	public static Vc getVc(int width, int height, int count) {

		return getVc(width, height, count, DEFAULT_BG);
	}

	/**
	 * 获取图片验证对象
	 * 
	 * @param width 图片宽度
	 * @param height 图片高度
	 * @param count 字符数量
	 * @param bg 背景颜色
	 * @return 图片验证对象
	 */
	public static Vc getVc(int width, int height, int count, Color bg) {

		return getVc(width, height, count, bg, DEFAULT_CODES);
	}

	/**
	 * 获取图片验证对象
	 * 
	 * @param width 图片宽度
	 * @param height 图片高度
	 * @param count 字符数量
	 * @param bg 背景颜色
	 * @param codes 代码列表
	 * @return 图片验证对象
	 */
	public static Vc getVc(int width, int height, int count, Color bg, Character[] codes) {

		return getVc(width, height, count, bg, codes, DEFAULT_COLORS);
	}

	/**
	 * 获取图片验证对象
	 * 
	 * @param width 图片宽度
	 * @param height 图片高度
	 * @param count 字符数量
	 * @param bg 背景颜色
	 * @param codes 代码列表
	 * @param colors 颜色列表
	 * @return 图片验证对象
	 */
	public static Vc getVc(int width, int height, int count, Color bg, Character[] codes, Color[] colors) {

		return getVc(width, height, count, bg, codes, colors, DEFAULT_FONTS, DEFAULT_STYLES);
	}

	/**
	 * 获取图片验证对象
	 * 
	 * @param width 图片宽度
	 * @param height 图片高度
	 * @param count 字符数量
	 * @param bg 背景颜色
	 * @param codes 代码列表
	 * @param colors 颜色列表
	 * @param fonts 字体列表
	 * @param styles 字体样式列表
	 * @return 图片验证对象
	 */
	public static Vc getVc(int width, int height, int count, Color bg, Character[] codes, Color[] colors,
			String[] fonts, Integer[] styles) {

		// 图片对象
		BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		// 图形处理对象
		Graphics2D g2d = img.createGraphics();

		// 设置图片信息
		g2d.setColor(bg);
		g2d.fillRect(0, 0, width, height);

		// 字符宽度
		int charWidth = (int) (width * PROP / count);
		// 字体大小
		int fontSize = (int) (height * PROP);

		// 字符x坐标位置
		int x = (int) (width * (1 - PROP) / 2);
		// 字符y坐标位置
		int y = (int) (height * (1 - PROP) / 2 + fontSize * (1 - CHAR_BLANK_PROP));
		// 代码
		StringBuilder code = new StringBuilder();
		for (int i = 0; i < count; i++) {
			// 随机获取字符
			char c = random(codes);
			code.append(c);
			// 设置随机颜色
			g2d.setColor(random(colors));
			// 设置随机字体
			g2d.setFont(new Font(random(fonts), random(styles), fontSize));
			// 添加字符
			g2d.drawString(String.valueOf(c), x + i * charWidth, y);
		}

		// 设置干扰线
		// 设置随机颜色
		g2d.setColor(random(colors));
		// 随机高度
		int lineY = height - random.nextInt(height);
		// 添加干扰线
		g2d.drawLine(0, lineY, width, height - lineY);

		return new Vc(code.toString(), img);
	}

	/**
	 * 随机获取数组中对象
	 * 
	 * @param arr 数组
	 * @return 随机对象
	 */
	private static <T> T random(T[] arr) {

		return arr[random.nextInt(arr.length)];
	}

	/**
	 * 图片对象写入流
	 * 
	 * @param img 图片对象
	 * @param os 流
	 * @throws IOException io异常
	 */
	public static void write(BufferedImage img, OutputStream os) throws IOException {

		ImageIO.write(img, "png", os);
	}

	/**
	 * 图片验证信息
	 *
	 * @author 张成轩
	 */
	public static class Vc {

		private String code;
		private BufferedImage img;

		private Vc(String code, BufferedImage img) {

			this.code = code;
			this.img = img;
		}

		/**
		 * @return 代码
		 */
		public String getCode() {

			return code;
		}

		/**
		 * @return 图片对象
		 */
		public BufferedImage getImg() {

			return img;
		}
	}
}
